package com.hcy.rabbitmanagerapi.utils;

import com.alibaba.fastjson.JSON;
import com.hcy.rabbitbasicmodel.enums.Log_Code;
import com.hcy.rabbitbasicmodel.model.ReturnResult;
import com.hcy.userclient.client.UserAuthClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Author huchenying
 * @Description 上传操作日志
 * @Date 2022/4/21 20:38
 */
@Component
@Aspect
@Slf4j
public class UploadOptLog {

    @Autowired
    UserAuthClient userAuthClient;

    private final ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 8, 1, TimeUnit.HOURS, new LinkedBlockingQueue<>()
            , r -> {
        Thread thread = new Thread(r);
        thread.setName("autoLog");
        return thread;
    }, new ThreadPoolExecutor.CallerRunsPolicy());

    @Autowired
    CheckTokenAccess checkTokenAccess;

    @Pointcut("@annotation(com.hcy.rabbitmanagerapi.utils.MyAutoOptLog)")
    public void cut() {

    }

    @Around("cut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object proceed = joinPoint.proceed();
        ReturnResult returnResult = (ReturnResult) proceed;
        //如果方法返回结果是不成功
        if (!returnResult.isSuccess()) {
            return returnResult;
        }
        //获取request对象
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        Object[] args = joinPoint.getArgs();//拿到方法的参数
        String param = JSON.toJSONString(args);
//        String requestURI = request.getRequestURI();//拿到请求的url
        //获取对象头中的这个信息
        String authorization = request.getHeader("Authorization");
        if (authorization != null) {
            authorization = authorization.substring(7);
        }
        log.info("通过切面获取的token = [{}]", authorization);
        //通过token获取用户名
        String username = checkTokenAccess.getUsernameByToken(authorization);

        //1.1获取目标对象对应的字节码对象
        Class<?> targetCls = joinPoint.getTarget().getClass();
        //1.2获取目标方法对象
        //1.2.1 获取方法签名信息从而获取方法名和参数类型
        Signature signature = joinPoint.getSignature();
        //1.2.1.1将方法签名强转成MethodSignature类型，方便调用
        MethodSignature ms = (MethodSignature) signature;
        //1.2.2通过字节码对象以及方法签名获取目标方法对象
        Method targetMethod = targetCls.getDeclaredMethod(ms.getName(), ms.getParameterTypes());
        //1.3获取目标方法对象上注解中的属性值
        //1.2.3 获取方法上的自定义requiredLog注解
        MyAutoOptLog myAutoOptLog = targetMethod.getAnnotation(MyAutoOptLog.class);
        //1.2.4 获取自定义注解中operation属性的值
        Log_Code log_code = myAutoOptLog.value();

        //提交执行
        submit(log_code,username,param);
        return returnResult;
    }

    public void submit(Log_Code log_code, String username,String remark) {
        log.info("提交操作日志执行 username -> {}", username);
        executor.submit(new AutoLogUpload(userAuthClient,log_code,username,remark));
    }

//    @AfterReturning(value = "@annotation(com.hcy.rabbitmanagerapi.utils.MyAutoOptLog)", returning = "methodResult")
//    public void exec(JoinPoint point, Object methodResult) {
//        MethodSignature ms = (MethodSignature) point.getSignature();
//        Method method = ms.getMethod();
//
//        System.out.println("请求方法为：" + method.getName());
//        System.out.println("请求返回内容为：" + methodResult.toString());
//
//    }

}
